﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Net.Mail;
using DIT.Utility;
using Domain = DIT.Domain;

namespace DIT.Client.Common.Model
{
    public class AccountModel : INotifier, IDataErrorInfo
    {
        public Domain.Account AccountEntity = null;
        private string[] propertyListForValidation = new string[]
        { "PAN", "SurNameOrOrgName", "FirstName", "MiddleName", "OrgOldName", "PinCode", "CityOrTownOrDistrict", "EmailAddress", "MobileNo", "STD", "PhoneNo", "DOB" };

        public AccountModel(Domain.Account account)
        {
            AccountEntity = account;

            Set();
        }

        private void Set()
        {
            ID = AccountEntity.ID;
            TaxPayerType = AccountEntity.TaxPayerType;
            PAN = AccountEntity.PAN;
            SurNameOrOrgName = AccountEntity.AccountInfo.AssesseeName.SurNameOrOrgName;
            FirstName = AccountEntity.AccountInfo.AssesseeName.FirstName;
            MiddleName = AccountEntity.AccountInfo.AssesseeName.MiddleName;
            OrgOldName = AccountEntity.AccountInfo.AssesseeName.OrgOldName;
            PinCode = AccountEntity.AccountInfo.Address.PinCode;
            ResidenceName = AccountEntity.AccountInfo.Address.ResidenceName;
            ResidenceNo = AccountEntity.AccountInfo.Address.ResidenceNo;
            RoadOrStreet = AccountEntity.AccountInfo.Address.RoadOrStreet;
            CityOrTownOrDistrict = AccountEntity.AccountInfo.Address.CityOrTownOrDistrict;
            EmailAddress = AccountEntity.AccountInfo.EmailAddress;
            LocalityOrArea = AccountEntity.AccountInfo.Address.LocalityOrArea;
            MobileNo = AccountEntity.AccountInfo.MobileNo;
            STD = AccountEntity.AccountInfo.Address.STDCode;
            PhoneNo = AccountEntity.AccountInfo.Address.PhoneNo;
            DOB = AccountEntity.AccountInfo.DOB;
            EmployerCategory = AccountEntity.AccountInfo.EmployerCategory;
            Gender = AccountEntity.AccountInfo.Gender;
            StateCode = AccountEntity.AccountInfo.Address.StateCode;
            Status = AccountEntity.AccountInfo.Status;
        }

        public void Refresh()
        {
            Set();

            //RaisePropertyChangedEvent("SelectedClient");
        }
        public void Update()
        {
            AccountEntity.PAN = this.PAN;
            AccountEntity.AccountInfo.AssesseeName = new Domain.AssesseeName(this.SurNameOrOrgName, this.FirstName, this.MiddleName, this.orgOldName);
            AccountEntity.AccountInfo.Address = new Domain.Address(this.ResidenceNo, this.localityOrArea, this.CityOrTownOrDistrict, this.StateCode, this.PinCode, this.ResidenceName, this.RoadOrStreet, this.STD, this.PhoneNo);
            AccountEntity.AccountInfo.EmailAddress = this.EmailAddress;
            AccountEntity.AccountInfo.MobileNo = this.MobileNo;
            AccountEntity.AccountInfo.DOB = this.DOB;
            AccountEntity.AccountInfo.EmployerCategory = this.EmployerCategory;
            AccountEntity.AccountInfo.Gender = this.Gender;
            AccountEntity.AccountInfo.Status = this.Status;
        }

        #region public Properties

        public Guid ID { get; set; }

        private bool isSelected;
        public bool IsSelected 
        {
            get { return isSelected; }
            set 
            {
                isSelected = value;
                RaisePropertyChangedEvent("IsSelected");
            } 
        }

        private Domain.TaxPayerTypeENUM taxPayerType;
        public Domain.TaxPayerTypeENUM TaxPayerType
        {
            get { return taxPayerType; }
            set
            {
                taxPayerType = value;
                RaisePropertyChangedEvent("TaxPayerType");
            }
        }

        private string pan;
        public string PAN
        {
            get { return pan; }
            set
            {
                pan = value;
                RaisePropertyChangedEvent("PAN");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string firstName;
        public string FirstName
        {
            get { return firstName; }
            set
            {
                firstName = value;
                RaisePropertyChangedEvent("FirstName");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string middleName;
        public string MiddleName
        {
            get { return middleName; }
            set
            {
                middleName = value;
                RaisePropertyChangedEvent("MiddleName");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string surNameOrOrgName;
        public string SurNameOrOrgName
        {
            get { return surNameOrOrgName; }
            set
            {
                surNameOrOrgName = value;
                RaisePropertyChangedEvent("SurNameOrOrgName");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string orgOldName;
        public string OrgOldName
        {
            get { return orgOldName; }
            set
            {
                orgOldName = value;
                RaisePropertyChangedEvent("OrgOldName");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string residenceNo;
        public string ResidenceNo
        {
            get { return residenceNo; }
            set
            {
                residenceNo = value;
                RaisePropertyChangedEvent("ResidenceNo");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string residenceName;
        public string ResidenceName
        {
            get { return residenceName; }
            set
            {
                residenceName = value;
                RaisePropertyChangedEvent("ResidenceName");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string roadOrStreet;
        public string RoadOrStreet
        {
            get { return roadOrStreet; }
            set
            {
                roadOrStreet = value;
                RaisePropertyChangedEvent("RoadOrStreet");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string localityOrArea;
        public string LocalityOrArea
        {
            get { return localityOrArea; }
            set
            {
                localityOrArea = value;
                RaisePropertyChangedEvent("LocalityOrArea");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string cityOrTownOrDistrict;
        public string CityOrTownOrDistrict
        {
            get { return cityOrTownOrDistrict; }
            set
            {
                cityOrTownOrDistrict = value;
                RaisePropertyChangedEvent("CityOrTownOrDistrict");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private Domain.StateCodeENUM? stateCode;
        public Domain.StateCodeENUM? StateCode
        {
            get { return stateCode; }
            set
            {
                stateCode = value;
                RaisePropertyChangedEvent("StateCode");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private ulong? pinCode;
        public ulong? PinCode
        {
            get { return pinCode; }
            set
            {
                pinCode = value;
                RaisePropertyChangedEvent("PinCode");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private ulong? phoneNo;
        public ulong? PhoneNo
        {
            get { return phoneNo; }
            set
            {
                phoneNo = value;
                RaisePropertyChangedEvent("PhoneNo");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private ulong? std;
        public ulong? STD
        {
            get { return std; }
            set
            {
                std = value;
                RaisePropertyChangedEvent("STD");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private ulong? mobileNo;
        public ulong? MobileNo
        {
            get { return mobileNo; }
            set
            {
                mobileNo = value;
                RaisePropertyChangedEvent("MobileNo");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private string emailAddress;
        public string EmailAddress
        {
            get { return emailAddress; }
            set
            {
                emailAddress = value;
                RaisePropertyChangedEvent("EmailAddress");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private DateTime? dob;
        public DateTime? DOB
        {
            get { return dob; }
            set
            {
                dob = value;
                RaisePropertyChangedEvent("DOB");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private Domain.EmployerCategoryENUM? employerCategory;
        public Domain.EmployerCategoryENUM? EmployerCategory
        {
            get { return employerCategory; }
            set
            {
                employerCategory = value;
                RaisePropertyChangedEvent("EmployerCategory");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private Domain.GenderENUM? gender;
        public Domain.GenderENUM? Gender
        {
            get { return gender; }
            set
            {
                gender = value;
                RaisePropertyChangedEvent("Gender");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        private Domain.StatusENUM? status;
        public Domain.StatusENUM? Status
        {
            get { return status; }
            set
            {
                status = value;
                RaisePropertyChangedEvent("Status");
                RaisePropertyChangedEvent("IsDirty");
                RaisePropertyChangedEvent("IsValid");
            }
        }

        public string DisplayName
        {
            get
            {
                if (string.IsNullOrWhiteSpace(FirstName) || string.IsNullOrWhiteSpace(FirstName) && string.IsNullOrWhiteSpace(MiddleName))
                    return SurNameOrOrgName;
                else if (string.IsNullOrWhiteSpace(MiddleName))
                    return SurNameOrOrgName + ", " + FirstName;
                else if (!string.IsNullOrWhiteSpace(FirstName) && !string.IsNullOrWhiteSpace(MiddleName))
                    return SurNameOrOrgName + ", " + FirstName + " " + MiddleName;
                else
                    return null;
            }
        }
        public bool IsValid
        {
            get
            {
                StringBuilder errorStringBuilder = new StringBuilder();
                foreach (string property in propertyListForValidation)
                {
                    string propError = this[property];
                    if (!string.IsNullOrWhiteSpace(propError))
                        errorStringBuilder.AppendLine(this[property]);
                }
                Error = errorStringBuilder.ToString().Trim().TrimEnd(new char[] { '\r', '\n' });
                return string.IsNullOrWhiteSpace(Error);
            }
        }
        public bool IsDirty
        {
            get
            {
                bool isDirty = false;

                isDirty = !(AccountEntity.PAN + string.Empty).Equals(this.PAN, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.AssesseeName.SurNameOrOrgName + string.Empty).Equals(this.SurNameOrOrgName + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.AssesseeName.FirstName + string.Empty).Equals(this.FirstName + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.AssesseeName.MiddleName + string.Empty).Equals(this.MiddleName + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.AssesseeName.OrgOldName + string.Empty).Equals(this.OrgOldName + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || AccountEntity.AccountInfo.Address.PinCode != this.PinCode;
                isDirty = isDirty || !(AccountEntity.AccountInfo.Address.ResidenceName + string.Empty).Equals(this.ResidenceName + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.Address.ResidenceNo + string.Empty).Equals(this.ResidenceNo + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.Address.RoadOrStreet + string.Empty).Equals(this.RoadOrStreet + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.Address.CityOrTownOrDistrict + string.Empty).Equals(this.CityOrTownOrDistrict + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.EmailAddress + string.Empty).Equals(this.EmailAddress + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || !(AccountEntity.AccountInfo.Address.LocalityOrArea + string.Empty).Equals(this.LocalityOrArea + string.Empty, StringComparison.CurrentCultureIgnoreCase);
                isDirty = isDirty || AccountEntity.AccountInfo.MobileNo != this.MobileNo;
                isDirty = isDirty || AccountEntity.AccountInfo.Address.STDCode != this.STD;
                isDirty = isDirty || AccountEntity.AccountInfo.Address.PhoneNo != this.PhoneNo;
                isDirty = isDirty || AccountEntity.AccountInfo.DOB != this.DOB;
                isDirty = isDirty || AccountEntity.AccountInfo.EmployerCategory != this.EmployerCategory;
                isDirty = isDirty || AccountEntity.AccountInfo.Gender != this.Gender;
                isDirty = isDirty || AccountEntity.AccountInfo.Address.StateCode != this.StateCode;
                isDirty = isDirty || AccountEntity.AccountInfo.Status != this.Status;

                return isDirty;
            }
        }
        public bool IsNew { get { return ID == Guid.Empty; } }
        #endregion
        
        #region Error Handling
        private string errorString;
        public string Error { get { return errorString; } set { errorString = value; RaisePropertyChangedEvent("Error"); } }
        public string this[string columnName]
        {
            get
            {
                switch (columnName)
                {
                    case "PAN":
                        return this.ValidatePAN();
                    case "SurNameOrOrgName":
                        return this.ValidateSurNameOrOrgName();
                    case "FirstName":
                        return this.ValidateFirstName();
                    case "MiddleName":
                        return this.ValidateMiddleName();
                    case "PinCode":
                        return this.ValidatePinCode();
                    case "CityOrTownOrDistrict":
                        return this.ValidateCityOrTownOrDistrict();
                    case "EmailAddress":
                        return this.ValidateEmailAddress();
                    case "MobileNo":
                        return this.ValidateMobileNo();
                    case "STD":
                        return this.ValidateSTD();
                    case "PhoneNo":
                        return this.ValidatePhoneNo();
                    case "DOB":
                        return this.ValidateDOB();
                    default:
                        return null;
                }
            }
        }
        #endregion

        #region Property Validation
        private string ValidatePAN()
        {
            if (!string.IsNullOrWhiteSpace(this.PAN))
            {
                if (this.PAN.Length != 10 || !(new Regex(DITConfig.AppSettings["PANValidatorRegx"]).IsMatch(this.PAN)))
                    return DITConfig.AppSettings["InvalidPAN"];
            }
            return null;
        }
        private string ValidateSurNameOrOrgName()
        {
            if (string.IsNullOrWhiteSpace(SurNameOrOrgName))
                return DITConfig.AppSettings["MandatorySurNameOrgName"];
            return null;
        }
        private string ValidateFirstName()
        {
            return null;
        }
        private string ValidateMiddleName()
        {
            return null;
        }
        private string ValidatePinCode()
        {
            if (this.PinCode != null)
            {
                if (!(new Regex(DITConfig.AppSettings["PinCodeValidatorRegx"]).IsMatch(this.PinCode + string.Empty)))
                    return DITConfig.AppSettings["InvalidPinCode"];
            }
            return null;
        }
        private string ValidateCityOrTownOrDistrict()
        {
            return null;
        }
        private string ValidateEmailAddress()
        {
            if (!string.IsNullOrWhiteSpace(this.EmailAddress))
            {
                if (!(new Regex(DITConfig.AppSettings["EmailValidatorRegx"]).IsMatch(this.EmailAddress + string.Empty)))
                    return DITConfig.AppSettings["InvalidEmailAddress"];
                //try
                //{
                //    MailAddress addr = new MailAddress(this.EmailAddress);
                //}
                //catch (FormatException)
                //{
                //    return DITConfig.AppSettings["InvalidEmailAddress"];
                //}
            }
            return null;
        }
        private string ValidateMobileNo()
        {
            if (this.MobileNo != null)
            {
                if (!(new Regex(DITConfig.AppSettings["MobileValidatorRegx"]).IsMatch(this.MobileNo + string.Empty)))
                    return DITConfig.AppSettings["InvalidMobileNo"];
            }
            return null;
        }
        private string ValidateSTD()
        {
            if (this.STD != null)
            {
                if (!(new Regex(DITConfig.AppSettings["STDValidatorRegx"]).IsMatch((this.STD + string.Empty).PadLeft(3, '0'))))
                    return DITConfig.AppSettings["InvalidSTD"];
            }
            return null;
        }
        private string ValidatePhoneNo()
        {
            if (this.PhoneNo != null)
            {
                if (!(new Regex(DITConfig.AppSettings["PhoneValidatorRegx"]).IsMatch(this.PhoneNo + string.Empty)))
                    return DITConfig.AppSettings["InvalidPhone"];
            }
            return null;
        }
        private string ValidateDOB()
        {
            if (this.DOB != null)
            {
                if (this.DOB.Value >= DateTime.Today)
                    return DITConfig.AppSettings["InvalidDOB"];
            }
            return null;
        }
        #endregion
    }
}
